from IPython.core.interactiveshell import InteractiveShell
import sys
from io import StringIO
"""
python 代码执行类
该类为单例模式类似一个工厂类，提供InteractiveShell实例给用户，实现用户代码运行环境的有效隔离
"""
class CodeExecute:
    _instance = None
    __user_shells = {}
    
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        pass

    def __get_shell(self, user_id):
        if user_id not in self.__user_shells:
            user_namespace = {}
            shell = InteractiveShell(user_ns=user_namespace)
            self.__user_shells[user_id] = {'shell': shell, 'namespace': user_namespace}
        shell.user_ns=self.__user_shells[user_id]['namespace']
        return self.__user_shells[user_id]
    
    def delete_shell(self, user_id):
        if user_id in self.__user_shells:
            del self.__user_shells[user_id]
            return {'message': 'Shell deleted'}
    
    

    def execute_code(self, user_id, code):
        try:
            # 创建一个字符串缓冲区来捕获标准输出
            output_buffer = StringIO()
            old_stdout = sys.stdout  # 保存原始的标准输出
            sys.stdout = output_buffer  # 将标准输出重定向到缓冲区

            shell_info = self.__get_shell(user_id)
            shell = shell_info['shell']
            user_namespace = shell_info['namespace']
            # 执行代码并捕获结果
            result = shell.run_cell(code)

            # 恢复标准输出
            sys.stdout = old_stdout

            # 获取捕获的 print 输出
            captured_output = output_buffer.getvalue()

            # 获取交互式 shell 的历史输出
            shell_output = ""
            for stream in shell.user_ns.get('_oh', []):
                shell_output += str(shell.user_ns['_oh'][stream]) + "\n"

            # 检查是否有错误
            if result.error_in_exec:
                return {
                    'success': False,
                    'error': str(result.error_in_exec),
                    'output': captured_output  # 返回捕获的输出
                }

            # 返回成功结果
            return {
                'success': True,
                'output': captured_output,  # 返回捕获的 print 输出
                'shell_output': shell_output.strip(),  # 返回交互式 shell 的输出
                'result': str(result.result) if result.result else None,
                'namespace': {k: str(v) for k, v in user_namespace.items() if not k.startswith('_')}  # 返回用户命名空间
            }

        except Exception as e:
            # 恢复标准输出以防异常发生
            sys.stdout = old_stdout
            return {
                'success': False,
                'error': str(e),
                'output': output_buffer.getvalue()  # 返回捕获的输出
            }

codeExecute = CodeExecute()